namespace Rage.Base.Abilities
{
    using System;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;

    public enum SpecialEffectDataType { AverageStats, Uptime };
    public enum AttackTableSelector { Missed = 0, Dodged, Parried, Blocked, Critical, Hit }
    public enum StatType { Unbuffed, Buffed, Average, Maximum };
    public enum Hand { MH = 0, OH, Both };
    public enum AttackType { Yellow = 0, White, Both };

    public abstract class ClassAbility
    {
        // Constructors
        protected ClassAbility()
        {
            // Character related
            //CollChar = null;
            //CollChar.Char = null;
            //CollChar.StatS = null;
            //CollChar.CombatFactors = null;
            //MHAtkTable = null;
            //OHAtkTable = null;
            //CollChar.Whiteattacks = null;
            //CollChar.CalcOpts = null;
            //CollChar.BossOpts = null;
            // ClassAbility Related
            ReqTalent = false;
            CanBeDodged = true;
            CanBeParried = true;
            CanBeShielded = true;
            CanCrit = true;
            CanMiss = true;
            Talent2ChksValue = 0;
            AbilIterater = -1;
            ReqMeleeWeap = false;
            ReqMeleeRange = false;
            ReqMultiTargs = false;
            Targets = 1f;
            MaxRange = 5f; // In Yards 
            CD = -1f; // In Seconds
            Duration = 0; // In Seconds
            ResourceCost = 0;
            CastTime = -1f; // In Seconds
            GCDTime = 1.5f; // default GCD size
            StanceOkFury = false;
            StanceOkArms = false;
            StanceOkDef = false;
            UseReact = false;
            DamageBase = 0f;
            DamageBonus = 1f;
            HealingBase = 0f;
            HealingBonus = 1f;
            //BonusCritChance = 0.00f;
            BonusCritDamage = 1f;
            UseForceTechHit = false;
            UseHitTable = true;
            validatedSet = false;
            SwingsOffHand = false;
            SwingsPerActivate = 1f;
            UsesGCD = true;
        }
        public static ClassAbility NULL = new NullAbility();
        #region Variables
        public int AbilIterater;
        #endregion
        #region Get/Set
        public static string SName { get { return "Invalid"; } }
        public static string SDesc { get { return "Invalid"; } }
        public static string SIcon { get { return "trade_engineering"; } }
        public static string SFqn { get { return "Invalid"; } }
        public static int SSpellId { get { return 0; } }
        public virtual string Name { get { return SName; } }
        public virtual string Desc { get { return SDesc; } }
        public virtual string Icon { get { return SIcon; } }
        public virtual string Fqn { get { return SFqn; } }
        public virtual int SpellId { get { return SSpellId; } }
        protected bool ReqTalent { get; set; }
        protected int Talent2ChksValue { get; set; }
        public bool ReqMeleeWeap { get; set; }
        public bool ReqMeleeRange { get; set; }
        public bool CallsForOffhand { get; set; }
        protected bool ReqMultiTargs { get; set; }
        private float _avgTargets = -1f;
        public float AvgTargets {
            get {
                if (_avgTargets == -1f && Targets != -1) {
                    if (CollChar.BossOpts.MultiTargs && CollChar.BossOpts.Targets != null && CollChar.BossOpts.Targets.Count > 0) {
                        float value = 0;
                        foreach (TargetGroup tg in CollChar.BossOpts.Targets) {
                            if (!tg.Validate) { continue; } // Bad one, skip it
                            if (!tg.AffectsRole[PLAYER_ROLES.MeleeDPS]) { continue; } // Doesn't apply to us
                            float upTime = ((CollChar.BossOpts.BerserkTimer / tg.Frequency) * (tg.Duration / 1000f)) / CollChar.BossOpts.BerserkTimer
                                   * tg.Chance // Chance it happens to us
                                   * tg.FightUptimePercent; // The Phase uptime
                            value += (Math.Min(10 - (tg.NearBoss ? 1 : 0), Math.Min(Targets - (tg.NearBoss ? 1 : 0), tg.NumTargs - (tg.NearBoss ? 1 : 0) + CollChar.StatS.BonusTargets))) * upTime;
                        }
                        _avgTargets = 1f + value;
                    } else { _avgTargets = 1f; }
                }
                return _avgTargets;
            }
        }
        /// <summary>
        /// The maximum number of targets this ability would normally hit without any other bonues like Sweeping Strikes.<br/>
        /// Eg- Mortal Strike would normally only hit one target, Whirlwind would hit four.
        /// Sweeping Strikes would increase these numbers but that should not be included here.
        /// </summary>
        public float Targets { get; protected set; }
        public Maintenance AbilIterator { get; set; }
        public string AbilityTokens { get; set; } // Modifies the ability in some way
        public string TalentTokens { get; set; }
        public float ApCost { get; set; }
        public GomLib.Models.ApType ApType { get; set; }
        public float CastingTime { get; set; } // In Seconds
        public float ChannelingTime { get; set; } // In Seconds
        public float Cooldown { get { return CD; } set { CD = value; } } // In Seconds
        public long DescriptionId { get; set; }
        public float EnergyCost { get; set; }
        public float ForceCost { get; set; }
        public float GCD { get; set; }
        public bool GcdOverride { get; set; }
        public bool IgnoreAlacrity { get; set; }
        public bool UseSecCoeff { get; set; }
        public bool HighThreat { get; set; }
        public bool IsHidden { get; set; }
        public bool MustTargetSlowedOrImmobilized { get; set; }
        public bool MustTargetIncapacitated { get; set; }
        public bool IsPassive { get; set; }
        public float Level { get; set; }
        public bool LineOfSightCheck { get; set; }
        public long ModalGroup { get; set; }
        public int NameId { get; set; }
        public ulong NodeId { get; set; }
        public bool Pushback { get; set; }
        public ulong SharedCooldown { get; set; }
        public int TargetArc { get; set; }
        public int TargetArcOffset { get; set; }
        public GomLib.Models.TargetRule TargetRule { get; set; }
        public bool CanBeDodged { get; protected set; }
        public bool CanBeParried { get; protected set; }
        public bool CanBeShielded { get; protected set; }
        public bool CanCrit { get; protected set; }
        public bool CanMiss { get; protected set; }
        public float MinRange { get; protected set; } // In Yards 
        public float MaxRange { get; protected set; } // In Yards
        public float CD { get; set; }
        public float Duration { get; protected set; } // In Seconds
        public float ResourceCost {
            get {
                if (ApType == GomLib.Models.ApType.Rage) {
                    return ApCost;
                } else if (ApType == GomLib.Models.ApType.None) {
                    return ForceCost;
                } else {
                    return EnergyCost;
                }
            }
            protected set {
                if (ApType == GomLib.Models.ApType.Rage) {
                    ApCost = value;
                } else if (ApType == GomLib.Models.ApType.None) {
                    ForceCost = value;
                } else {
                    EnergyCost = value;
                }
            }
        }
        protected float _cachedCastTime = -1f;
        public float CastTime // In Seconds
        {
            get { return _cachedCastTime; }
            protected set {
                _cachedCastTime = value;
                _cachedUseTime = /*(CollChar.CalcOpts == null ? 0f : 0f/*CollChar.CalcOpts.Latency + (UseReact ? CollChar.CalcOpts.React / 1000f : CollChar.CalcOpts.AllowedReact)*//*)
                    +*/ Math.Min(Math.Max(1.5f, value), _cachedGCDTime);
            }
        }
        protected float _cachedGCDTime = 1.5f;
        public float GCDTime // In Seconds
        {
            get { return _cachedGCDTime; }
            protected set
            {
                _cachedGCDTime = value;
                _cachedUseTime = /*(CollChar.CalcOpts != null ? 0f/*CollChar.CalcOpts.Latency + (UseReact ? CollChar.CalcOpts.React / 1000f : CollChar.CalcOpts.AllowedReact)*//* : 0f)
                    +*/ Math.Min(Math.Max(1.5f, _cachedCastTime), value);
            }
        }
        protected float _cachedUseTime = 0;
        public float UseTime { get { return _cachedUseTime; } }
#if FALSE
        /// <summary>
        /// <Jothay> Trying to make sense of the Ability/Talent Tokens values
        /// <Jothay> damage,s,1,1.87,0.167,0.207,0.01
        /// <Jothay> What is all that?
        /// <Jothay> That's for "abl.sith_warrior.force_scream"
        /// <nohh> in this case it's damage/healing,weapon/spell damage,multiplier,coefficient,hpMin,hpMax,modPct
        /// <Jothay> so that means that Force Scream is doing Spell Damage with a 100% multiplier at a 1.87 coeff of attack power,
        /// and does minimum 0.167 damage and maximum 0.207 damage and is modified by 1% (so divided by 100)?
        /// <nohh> and the formula is minDmg = Math.round(multiplier * (coefficient * CharactersDamageBonus + hpMin * stdDmg))
        /// where stdDmg is a value from the lookup table cbtStandardDamageInfo (that's a node name)
        /// <nohh> the multiplier is for DoTs and such that do their damage multiple times
        /// <nohh> to show the total damage
        /// <nohh> some other talents will have tokens like
        /// 'damage,A,B,C' where A == multiplier, B == amtMin, C == amtMax, and the formula is multiplier*amtMin for min damage and multiplier*amtMax for max damage
        /// for abilities (like the new proc trinkets) that do a fixed amount of damage
        /// <nohh> or some other abilities, idk if any talents use that formula
        /// <Jothay> ok
        /// <nohh> healing is either 'healing,A,B,C', for a fixed value same as the damage, or
        /// 'healing,A,B,C,D', A = multiplier, B = coeff, C = hpMin, D = hpMax and tooltip value
        /// (for min) is Math.round(multiplier * (coeff * CharactersHealBonus + hpMin * stdHealing)
        /// stdHealing being a value from the cbtStandardHealingInfo lookup table
        /// <nohh> for trained abilities the stdHealing/stdDamage numbers are based off the rank of the skill used, so if a player is
        /// using Rank X which is acquired at level 32, you'll use the stdDamage/Healing value for Players of level 32, regardless of
        /// the person's actual level
        /// <Jothay> I'm going to assume everything trained to max
        /// <Jothay> Since the tool is for 50's
        /// <Jothay> If they aren't seeing the same numbers, its because they need to train up
        /// <nohh> for talents I think it's SUPPOSED to scale with your level, but the way it actually works is it uses a fixed value
        /// based off how many points are required to learn the talent
        /// <nohh> so a talent ability unlocked at 11 talent points will use the stdDamage/Healing value for a level 20 player,
        /// regardless of player level
        /// <nohh> I think that's wrong, idk if that's how the actual damage is calculated on the server, but that's how it appears
        /// on the client.. I got a response back from GZ asking about that actually and his response made me think it was wrong but
        /// AFAIK the talents in game still work as I described
        /// <Jothay> ok
        /// <Jothay> We can do DPS meter testing to see if we can figure it out
        /// <nohh> some abilities also have additional contributions from offhand weapons, which I never really took into account
        /// <Jothay> Ya, I notices some stuff have the same link as the above twice in the same talents tokens statement
        /// </summary>
        public virtual void ProcessAbilityTokens()
        {
            if (string.IsNullOrEmpty(AbilityTokens)) { return; }
            List<string> tokens = new List<string>(AbilityTokens.Split(';'));
            foreach (string token in tokens)
            {
                // "damage,w,1,3.29,0.329,0.329,1.2"
                Regex DamageType = new Regex(@"(?<maintype>damage),"
                                           + @"(?<type>w|s),"
                                           + @"(?<multiplier>\d+(?:\.\d+)?),"
                                           + @"(?<APcoeff>\d+(?:\.\d+)?),"
                                           + @"(?<HPMin>\d+(?:\.\d+)?),"
                                           + @"(?<HPMax>\d+(?:\.\d+)?),"
                                           + @"(?<modPct>-?\d+(?:\.\d+)?)");
                // "healing,1,2.37,0.098,0.138"
                Regex HealingTypeA = new Regex(@"(?<maintype>healing)," // healing,
                                             + @"(?<multiplier>\d+(?:\.\d+)?)," // 1,
                                             + @"(?<HPMin>\d+(?:\.\d+)?)," // 0.098,
                                             + @"(?<HPMax>\d+(?:\.\d+)?)"); // 0.138,
                Regex HealingTypeB = new Regex(@"(?<maintype>healing)," // healing,
                                             + @"(?<multiplier>\d+(?:\.\d+)?)," // 1,
                                             + @"(?<APcoeff>\d+(?:\.\d+)?)," //  2.37,
                                             + @"(?<HPMin>\d+(?:\.\d+)?)," // 0.098,
                                             + @"(?<HPMax>\d+(?:\.\d+)?)"); // 0.138,
                Regex DurationType = new Regex(@"(?<type>duration),(?<value>\d+)");
                Regex RankType = new Regex(@"(?<type>rank),(?<value>\d+)");
                Match m;
                if ((m = DamageType.Match(token)).Success && DamageCoreCoeff == 0) {
                    DamageCoreType = m.Groups["type"].Value;
                    DamageCoreMultiplier = float.Parse(m.Groups["multiplier"].Value);
                    DamageCoreCoeff = float.Parse(m.Groups["APcoeff"].Value);
                    DamageCoreHPMin = float.Parse(m.Groups["HPMin"].Value);
                    DamageCoreHPMax = float.Parse(m.Groups["HPMax"].Value);
                    DamageCoreModPct = float.Parse(m.Groups["modPct"].Value);
                } else if ((m = DamageType.Match(token)).Success && DamageCoreCoeff != 0) {
                    DamageCoreType2 = m.Groups["type"].Value;
                    DamageCoreMultiplier2 = float.Parse(m.Groups["multiplier"].Value);
                    DamageCoreCoeff2 = float.Parse(m.Groups["APcoeff"].Value);
                    DamageCoreHPMin2 = float.Parse(m.Groups["HPMin"].Value);
                    DamageCoreHPMax2 = float.Parse(m.Groups["HPMax"].Value);
                    DamageCoreModPct2 = float.Parse(m.Groups["modPct"].Value);
                } else  if ((m = HealingTypeA.Match(token)).Success) {
                    HealingCoreMultiplier = float.Parse(m.Groups["multiplier"].Value);
                    HealingCoreHPMin = float.Parse(m.Groups["HPMin"].Value);
                    HealingCoreHPMax = float.Parse(m.Groups["HPMax"].Value);
                    //string minHlg = string.Format("{0:0.##%}*({1:0.##}*charHlgBonuses)", HealingCoreMultiplier, HealingCoreHPMin);
                    //string maxHlg = string.Format("{0:0.##%}*({1:0.##}*charHlgBonuses)", HealingCoreMultiplier, HealingCoreHPMax);
                    //values.Add(string.Format("{0}-{1}", minHlg, maxHlg));
                    // where stdDmg is a value from the lookup table cbtStandardDamageInfo (that's a node name)
                } else  if ((m = HealingTypeB.Match(token)).Success) {
                    HealingCoreMultiplier = float.Parse(m.Groups["multiplier"].Value);
                    HealingCoreCoeff = float.Parse(m.Groups["APcoeff"].Value);
                    HealingCoreHPMin = float.Parse(m.Groups["HPMin"].Value);
                    HealingCoreHPMax = float.Parse(m.Groups["HPMax"].Value);
                    //string minHlg = string.Format("{0:0.##%}*({1:0.##}*charHlgBonuses+{2:0.##}*StdHlg)", HealingCoreMultiplier2, HealingCoreCoeff2, HealingCoreHPMin2);
                    //string maxHlg = string.Format("{0:0.##%}*({1:0.##}*charHlgBonuses+{2:0.##}*StdHlg)", HealingCoreMultiplier2, HealingCoreCoeff2, HealingCoreHPMax2);
                    //values.Add(string.Format("{0}-{1}", minHlg, maxHlg));
                    // where stdDmg is a value from the lookup table cbtStandardDamageInfo (that's a node name)
                } else if ((m = DurationType.Match(token)).Success) {
                    Duration = float.Parse(m.Groups["value"].Value);
                } else if ((m = RankType.Match(token)).Success) {
                    //Rank = float.Parse(m.Groups["value"].Value);
                } else {
                    // Didn't Parse
                }
            }
        }
#endif
        //
        public List<string> DamageCoreType = new List<string>() { null, "", "", "", "", "", "", "", "", "", "", };
        public List<float> DamageCoreMultiplier = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreCoeff = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreHPMin = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreHPMax = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreThreatMod = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreFlurryBlowsMax = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreFlurryBlowsMin = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreModFixedMax = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreModFixedMin = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };
        public List<float> DamageCoreModPct = new List<float>() { -1f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, };

        public string DamageCoreType1 { get { return DamageCoreType[1]; } set { if (DamageCoreType[1] != value) { DamageCoreType[1] = value; } } }
        public float DamageCoreMultiplier1 { get { return DamageCoreMultiplier[1]; } set { if (DamageCoreMultiplier[1] != value) { DamageCoreMultiplier[1] = value; } } }
        public float DamageCoreCoeff1 { get { return DamageCoreCoeff[1]; } set { if (DamageCoreCoeff[1] != value) { DamageCoreCoeff[1] = value; } } }
        public float DamageCoreHPMin1 { get { return DamageCoreHPMin[1]; } set { if (DamageCoreHPMin[1] != value) { DamageCoreHPMin[1] = value; } } }
        public float DamageCoreHPMax1 { get { return DamageCoreHPMax[1]; } set { if (DamageCoreHPMax[1] != value) { DamageCoreHPMax[1] = value; } } }
        public float DamageCoreThreatMod1 { get { return DamageCoreThreatMod[1]; } set { if (DamageCoreThreatMod[1] != value) { DamageCoreThreatMod[1] = value; } } }
        public float DamageCoreFlurryBlowsMax1 { get { return DamageCoreFlurryBlowsMax[1]; } set { if (DamageCoreFlurryBlowsMax[1] != value) { DamageCoreFlurryBlowsMax[1] = value; } } }
        public float DamageCoreFlurryBlowsMin1 { get { return DamageCoreFlurryBlowsMin[1]; } set { if (DamageCoreFlurryBlowsMin[1] != value) { DamageCoreFlurryBlowsMin[1] = value; } } }
        public float DamageCoreModFixedMax1 { get { return DamageCoreModFixedMax[1]; } set { if (DamageCoreModFixedMax[1] != value) { DamageCoreModFixedMax[1] = value; } } }
        public float DamageCoreModFixedMin1 { get { return DamageCoreModFixedMin[1]; } set { if (DamageCoreModFixedMin[1] != value) { DamageCoreModFixedMin[1] = value; } } }
        public float DamageCoreModPct1 { get { return DamageCoreModPct[1]; } set { if (DamageCoreModPct[1] != value) { DamageCoreModPct[1] = value; } } }

        public string DamageCoreType2 { get { return DamageCoreType[2]; } set { if (DamageCoreType[2] != value) { DamageCoreType[2] = value; } } }
        public float DamageCoreMultiplier2 { get { return DamageCoreMultiplier[2]; } set { if (DamageCoreMultiplier[2] != value) { DamageCoreMultiplier[2] = value; } } }
        public float DamageCoreCoeff2 { get { return DamageCoreCoeff[2]; } set { if (DamageCoreCoeff[2] != value) { DamageCoreCoeff[2] = value; } } }
        public float DamageCoreHPMin2 { get { return DamageCoreHPMin[2]; } set { if (DamageCoreHPMin[2] != value) { DamageCoreHPMin[2] = value; } } }
        public float DamageCoreHPMax2 { get { return DamageCoreHPMax[2]; } set { if (DamageCoreHPMax[2] != value) { DamageCoreHPMax[2] = value; } } }
        public float DamageCoreThreatMod2 { get { return DamageCoreThreatMod[2]; } set { if (DamageCoreThreatMod[2] != value) { DamageCoreThreatMod[2] = value; } } }
        public float DamageCoreFlurryBlowsMax2 { get { return DamageCoreFlurryBlowsMax[2]; } set { if (DamageCoreFlurryBlowsMax[2] != value) { DamageCoreFlurryBlowsMax[2] = value; } } }
        public float DamageCoreFlurryBlowsMin2 { get { return DamageCoreFlurryBlowsMin[2]; } set { if (DamageCoreFlurryBlowsMin[2] != value) { DamageCoreFlurryBlowsMin[2] = value; } } }
        public float DamageCoreModFixedMax2 { get { return DamageCoreModFixedMax[2]; } set { if (DamageCoreModFixedMax[2] != value) { DamageCoreModFixedMax[2] = value; } } }
        public float DamageCoreModFixedMin2 { get { return DamageCoreModFixedMin[2]; } set { if (DamageCoreModFixedMin[2] != value) { DamageCoreModFixedMin[2] = value; } } }
        public float DamageCoreModPct2 { get { return DamageCoreModPct[2]; } set { if (DamageCoreModPct[2] != value) { DamageCoreModPct[2] = value; } } }

        public string DamageCoreType3 { get { return DamageCoreType[3]; } set { if (DamageCoreType[3] != value) { DamageCoreType[3] = value; } } }
        public float DamageCoreMultiplier3 { get { return DamageCoreMultiplier[3]; } set { if (DamageCoreMultiplier[3] != value) { DamageCoreMultiplier[3] = value; } } }
        public float DamageCoreCoeff3 { get { return DamageCoreCoeff[3]; } set { if (DamageCoreCoeff[3] != value) { DamageCoreCoeff[3] = value; } } }
        public float DamageCoreHPMin3 { get { return DamageCoreHPMin[3]; } set { if (DamageCoreHPMin[3] != value) { DamageCoreHPMin[3] = value; } } }
        public float DamageCoreHPMax3 { get { return DamageCoreHPMax[3]; } set { if (DamageCoreHPMax[3] != value) { DamageCoreHPMax[3] = value; } } }
        public float DamageCoreThreatMod3 { get { return DamageCoreThreatMod[3]; } set { if (DamageCoreThreatMod[3] != value) { DamageCoreThreatMod[3] = value; } } }
        public float DamageCoreFlurryBlowsMax3 { get { return DamageCoreFlurryBlowsMax[3]; } set { if (DamageCoreFlurryBlowsMax[3] != value) { DamageCoreFlurryBlowsMax[3] = value; } } }
        public float DamageCoreFlurryBlowsMin3 { get { return DamageCoreFlurryBlowsMin[3]; } set { if (DamageCoreFlurryBlowsMin[3] != value) { DamageCoreFlurryBlowsMin[3] = value; } } }
        public float DamageCoreModFixedMax3 { get { return DamageCoreModFixedMax[3]; } set { if (DamageCoreModFixedMax[3] != value) { DamageCoreModFixedMax[3] = value; } } }
        public float DamageCoreModFixedMin3 { get { return DamageCoreModFixedMin[3]; } set { if (DamageCoreModFixedMin[3] != value) { DamageCoreModFixedMin[3] = value; } } }
        public float DamageCoreModPct3 { get { return DamageCoreModPct[3]; } set { if (DamageCoreModPct[3] != value) { DamageCoreModPct[3] = value; } } }

        public string DamageCoreType4 { get { return DamageCoreType[4]; } set { if (DamageCoreType[4] != value) { DamageCoreType[4] = value; } } }
        public float DamageCoreMultiplier4 { get { return DamageCoreMultiplier[4]; } set { if (DamageCoreMultiplier[4] != value) { DamageCoreMultiplier[4] = value; } } }
        public float DamageCoreCoeff4 { get { return DamageCoreCoeff[4]; } set { if (DamageCoreCoeff[4] != value) { DamageCoreCoeff[4] = value; } } }
        public float DamageCoreHPMin4 { get { return DamageCoreHPMin[4]; } set { if (DamageCoreHPMin[4] != value) { DamageCoreHPMin[4] = value; } } }
        public float DamageCoreHPMax4 { get { return DamageCoreHPMax[4]; } set { if (DamageCoreHPMax[4] != value) { DamageCoreHPMax[4] = value; } } }
        public float DamageCoreThreatMod4 { get { return DamageCoreThreatMod[4]; } set { if (DamageCoreThreatMod[4] != value) { DamageCoreThreatMod[4] = value; } } }
        public float DamageCoreFlurryBlowsMax4 { get { return DamageCoreFlurryBlowsMax[4]; } set { if (DamageCoreFlurryBlowsMax[4] != value) { DamageCoreFlurryBlowsMax[4] = value; } } }
        public float DamageCoreFlurryBlowsMin4 { get { return DamageCoreFlurryBlowsMin[4]; } set { if (DamageCoreFlurryBlowsMin[4] != value) { DamageCoreFlurryBlowsMin[4] = value; } } }
        public float DamageCoreModFixedMax4 { get { return DamageCoreModFixedMax[4]; } set { if (DamageCoreModFixedMax[4] != value) { DamageCoreModFixedMax[4] = value; } } }
        public float DamageCoreModFixedMin4 { get { return DamageCoreModFixedMin[4]; } set { if (DamageCoreModFixedMin[4] != value) { DamageCoreModFixedMin[4] = value; } } }
        public float DamageCoreModPct4 { get { return DamageCoreModPct[4]; } set { if (DamageCoreModPct[4] != value) { DamageCoreModPct[4] = value; } } }

        public string DamageCoreType5 { get { return DamageCoreType[5]; } set { if (DamageCoreType[5] != value) { DamageCoreType[5] = value; } } }
        public float DamageCoreMultiplier5 { get { return DamageCoreMultiplier[5]; } set { if (DamageCoreMultiplier[5] != value) { DamageCoreMultiplier[5] = value; } } }
        public float DamageCoreCoeff5 { get { return DamageCoreCoeff[5]; } set { if (DamageCoreCoeff[5] != value) { DamageCoreCoeff[5] = value; } } }
        public float DamageCoreHPMin5 { get { return DamageCoreHPMin[5]; } set { if (DamageCoreHPMin[5] != value) { DamageCoreHPMin[5] = value; } } }
        public float DamageCoreHPMax5 { get { return DamageCoreHPMax[5]; } set { if (DamageCoreHPMax[5] != value) { DamageCoreHPMax[5] = value; } } }
        public float DamageCoreThreatMod5 { get { return DamageCoreThreatMod[5]; } set { if (DamageCoreThreatMod[5] != value) { DamageCoreThreatMod[5] = value; } } }
        public float DamageCoreFlurryBlowsMax5 { get { return DamageCoreFlurryBlowsMax[5]; } set { if (DamageCoreFlurryBlowsMax[5] != value) { DamageCoreFlurryBlowsMax[5] = value; } } }
        public float DamageCoreFlurryBlowsMin5 { get { return DamageCoreFlurryBlowsMin[5]; } set { if (DamageCoreFlurryBlowsMin[5] != value) { DamageCoreFlurryBlowsMin[5] = value; } } }
        public float DamageCoreModFixedMax5 { get { return DamageCoreModFixedMax[5]; } set { if (DamageCoreModFixedMax[5] != value) { DamageCoreModFixedMax[5] = value; } } }
        public float DamageCoreModFixedMin5 { get { return DamageCoreModFixedMin[5]; } set { if (DamageCoreModFixedMin[5] != value) { DamageCoreModFixedMin[5] = value; } } }
        public float DamageCoreModPct5 { get { return DamageCoreModPct[5]; } set { if (DamageCoreModPct[5] != value) { DamageCoreModPct[5] = value; } } }

        public string DamageCoreType6 { get { return DamageCoreType[6]; } set { if (DamageCoreType[6] != value) { DamageCoreType[6] = value; } } }
        public float DamageCoreMultiplier6 { get { return DamageCoreMultiplier[6]; } set { if (DamageCoreMultiplier[6] != value) { DamageCoreMultiplier[6] = value; } } }
        public float DamageCoreCoeff6 { get { return DamageCoreCoeff[6]; } set { if (DamageCoreCoeff[6] != value) { DamageCoreCoeff[6] = value; } } }
        public float DamageCoreHPMin6 { get { return DamageCoreHPMin[6]; } set { if (DamageCoreHPMin[6] != value) { DamageCoreHPMin[6] = value; } } }
        public float DamageCoreHPMax6 { get { return DamageCoreHPMax[6]; } set { if (DamageCoreHPMax[6] != value) { DamageCoreHPMax[6] = value; } } }
        public float DamageCoreThreatMod6 { get { return DamageCoreThreatMod[6]; } set { if (DamageCoreThreatMod[6] != value) { DamageCoreThreatMod[6] = value; } } }
        public float DamageCoreFlurryBlowsMax6 { get { return DamageCoreFlurryBlowsMax[6]; } set { if (DamageCoreFlurryBlowsMax[6] != value) { DamageCoreFlurryBlowsMax[6] = value; } } }
        public float DamageCoreFlurryBlowsMin6 { get { return DamageCoreFlurryBlowsMin[6]; } set { if (DamageCoreFlurryBlowsMin[6] != value) { DamageCoreFlurryBlowsMin[6] = value; } } }
        public float DamageCoreModFixedMax6 { get { return DamageCoreModFixedMax[6]; } set { if (DamageCoreModFixedMax[6] != value) { DamageCoreModFixedMax[6] = value; } } }
        public float DamageCoreModFixedMin6 { get { return DamageCoreModFixedMin[6]; } set { if (DamageCoreModFixedMin[6] != value) { DamageCoreModFixedMin[6] = value; } } }
        public float DamageCoreModPct6 { get { return DamageCoreModPct[6]; } set { if (DamageCoreModPct[6] != value) { DamageCoreModPct[6] = value; } } }

        public string DamageCoreType7 { get { return DamageCoreType[7]; } set { if (DamageCoreType[7] != value) { DamageCoreType[7] = value; } } }
        public float DamageCoreMultiplier7 { get { return DamageCoreMultiplier[7]; } set { if (DamageCoreMultiplier[7] != value) { DamageCoreMultiplier[7] = value; } } }
        public float DamageCoreCoeff7 { get { return DamageCoreCoeff[7]; } set { if (DamageCoreCoeff[7] != value) { DamageCoreCoeff[7] = value; } } }
        public float DamageCoreHPMin7 { get { return DamageCoreHPMin[7]; } set { if (DamageCoreHPMin[7] != value) { DamageCoreHPMin[7] = value; } } }
        public float DamageCoreHPMax7 { get { return DamageCoreHPMax[7]; } set { if (DamageCoreHPMax[7] != value) { DamageCoreHPMax[7] = value; } } }
        public float DamageCoreThreatMod7 { get { return DamageCoreThreatMod[7]; } set { if (DamageCoreThreatMod[7] != value) { DamageCoreThreatMod[7] = value; } } }
        public float DamageCoreFlurryBlowsMax7 { get { return DamageCoreFlurryBlowsMax[7]; } set { if (DamageCoreFlurryBlowsMax[7] != value) { DamageCoreFlurryBlowsMax[7] = value; } } }
        public float DamageCoreFlurryBlowsMin7 { get { return DamageCoreFlurryBlowsMin[7]; } set { if (DamageCoreFlurryBlowsMin[7] != value) { DamageCoreFlurryBlowsMin[7] = value; } } }
        public float DamageCoreModFixedMax7 { get { return DamageCoreModFixedMax[7]; } set { if (DamageCoreModFixedMax[7] != value) { DamageCoreModFixedMax[7] = value; } } }
        public float DamageCoreModFixedMin7 { get { return DamageCoreModFixedMin[7]; } set { if (DamageCoreModFixedMin[7] != value) { DamageCoreModFixedMin[7] = value; } } }
        public float DamageCoreModPct7 { get { return DamageCoreModPct[7]; } set { if (DamageCoreModPct[7] != value) { DamageCoreModPct[7] = value; } } }

        public string DamageCoreType8 { get { return DamageCoreType[8]; } set { if (DamageCoreType[8] != value) { DamageCoreType[8] = value; } } }
        public float DamageCoreMultiplier8 { get { return DamageCoreMultiplier[8]; } set { if (DamageCoreMultiplier[8] != value) { DamageCoreMultiplier[8] = value; } } }
        public float DamageCoreCoeff8 { get { return DamageCoreCoeff[8]; } set { if (DamageCoreCoeff[8] != value) { DamageCoreCoeff[8] = value; } } }
        public float DamageCoreHPMin8 { get { return DamageCoreHPMin[8]; } set { if (DamageCoreHPMin[8] != value) { DamageCoreHPMin[8] = value; } } }
        public float DamageCoreHPMax8 { get { return DamageCoreHPMax[8]; } set { if (DamageCoreHPMax[8] != value) { DamageCoreHPMax[8] = value; } } }
        public float DamageCoreThreatMod8 { get { return DamageCoreThreatMod[8]; } set { if (DamageCoreThreatMod[8] != value) { DamageCoreThreatMod[8] = value; } } }
        public float DamageCoreFlurryBlowsMax8 { get { return DamageCoreFlurryBlowsMax[8]; } set { if (DamageCoreFlurryBlowsMax[8] != value) { DamageCoreFlurryBlowsMax[8] = value; } } }
        public float DamageCoreFlurryBlowsMin8 { get { return DamageCoreFlurryBlowsMin[8]; } set { if (DamageCoreFlurryBlowsMin[8] != value) { DamageCoreFlurryBlowsMin[8] = value; } } }
        public float DamageCoreModFixedMax8 { get { return DamageCoreModFixedMax[8]; } set { if (DamageCoreModFixedMax[8] != value) { DamageCoreModFixedMax[8] = value; } } }
        public float DamageCoreModFixedMin8 { get { return DamageCoreModFixedMin[8]; } set { if (DamageCoreModFixedMin[8] != value) { DamageCoreModFixedMin[8] = value; } } }
        public float DamageCoreModPct8 { get { return DamageCoreModPct[8]; } set { if (DamageCoreModPct[8] != value) { DamageCoreModPct[8] = value; } } }

        public string DamageCoreType9 { get { return DamageCoreType[9]; } set { if (DamageCoreType[9] != value) { DamageCoreType[9] = value; } } }
        public float DamageCoreMultiplier9 { get { return DamageCoreMultiplier[9]; } set { if (DamageCoreMultiplier[9] != value) { DamageCoreMultiplier[9] = value; } } }
        public float DamageCoreCoeff9 { get { return DamageCoreCoeff[9]; } set { if (DamageCoreCoeff[9] != value) { DamageCoreCoeff[9] = value; } } }
        public float DamageCoreHPMin9 { get { return DamageCoreHPMin[9]; } set { if (DamageCoreHPMin[9] != value) { DamageCoreHPMin[9] = value; } } }
        public float DamageCoreHPMax9 { get { return DamageCoreHPMax[9]; } set { if (DamageCoreHPMax[9] != value) { DamageCoreHPMax[9] = value; } } }
        public float DamageCoreThreatMod9 { get { return DamageCoreThreatMod[9]; } set { if (DamageCoreThreatMod[9] != value) { DamageCoreThreatMod[9] = value; } } }
        public float DamageCoreFlurryBlowsMax9 { get { return DamageCoreFlurryBlowsMax[9]; } set { if (DamageCoreFlurryBlowsMax[9] != value) { DamageCoreFlurryBlowsMax[9] = value; } } }
        public float DamageCoreFlurryBlowsMin9 { get { return DamageCoreFlurryBlowsMin[9]; } set { if (DamageCoreFlurryBlowsMin[9] != value) { DamageCoreFlurryBlowsMin[9] = value; } } }
        public float DamageCoreModFixedMax9 { get { return DamageCoreModFixedMax[9]; } set { if (DamageCoreModFixedMax[9] != value) { DamageCoreModFixedMax[9] = value; } } }
        public float DamageCoreModFixedMin9 { get { return DamageCoreModFixedMin[9]; } set { if (DamageCoreModFixedMin[9] != value) { DamageCoreModFixedMin[9] = value; } } }
        public float DamageCoreModPct9 { get { return DamageCoreModPct[9]; } set { if (DamageCoreModPct[9] != value) { DamageCoreModPct[9] = value; } } }

        public string DamageCoreType10 { get { return DamageCoreType[10]; } set { if (DamageCoreType[10] != value) { DamageCoreType[10] = value; } } }
        public float DamageCoreMultiplier10 { get { return DamageCoreMultiplier[10]; } set { if (DamageCoreMultiplier[10] != value) { DamageCoreMultiplier[10] = value; } } }
        public float DamageCoreCoeff10 { get { return DamageCoreCoeff[10]; } set { if (DamageCoreCoeff[10] != value) { DamageCoreCoeff[10] = value; } } }
        public float DamageCoreHPMin10 { get { return DamageCoreHPMin[10]; } set { if (DamageCoreHPMin[10] != value) { DamageCoreHPMin[10] = value; } } }
        public float DamageCoreHPMax10 { get { return DamageCoreHPMax[10]; } set { if (DamageCoreHPMax[10] != value) { DamageCoreHPMax[10] = value; } } }
        public float DamageCoreThreatMod10 { get { return DamageCoreThreatMod[10]; } set { if (DamageCoreThreatMod[0] != value) { DamageCoreThreatMod[10] = value; } } }
        public float DamageCoreFlurryBlowsMax10 { get { return DamageCoreFlurryBlowsMax[10]; } set { if (DamageCoreFlurryBlowsMax[10] != value) { DamageCoreFlurryBlowsMax[10] = value; } } }
        public float DamageCoreFlurryBlowsMin10 { get { return DamageCoreFlurryBlowsMin[10]; } set { if (DamageCoreFlurryBlowsMin[10] != value) { DamageCoreFlurryBlowsMin[10] = value; } } }
        public float DamageCoreModFixedMax10 { get { return DamageCoreModFixedMax[10]; } set { if (DamageCoreModFixedMax[10] != value) { DamageCoreModFixedMax[10] = value; } } }
        public float DamageCoreModFixedMin10 { get { return DamageCoreModFixedMin[10]; } set { if (DamageCoreModFixedMin[10] != value) { DamageCoreModFixedMin[10] = value; } } }
        public float DamageCoreModPct10 { get { return DamageCoreModPct[10]; } set { if (DamageCoreModPct[10] != value) { DamageCoreModPct[10] = value; } } }

        public virtual float HealingCoreMultiplier { get; set; }
        public virtual float HealingCoreCoeff { get; set; }
        public virtual float HealingCoreHPMin { get; set; }
        public virtual float HealingCoreHPMax { get; set; }
        //
#if FALSE
        public virtual void ApplyBonusModifications(float bonusDamageMultiplier, float bonusDamageValue,
            float bonusHealingDoneMultiplier, float bonusTargets,
            float bonusCooldownReduc, float bonusDuration, float bonusChannelReduc,
            float bonusConsumableCostReducMultiplier, float bonusConsumableCostReducValue,
            float bonusCritPerc, float bonusCritDamageMultiplier
            )
        {
            DamageBonus = 1f + bonusDamageMultiplier;
        }
        public virtual void ApplyPenaltyModifications(float penaltyDamageReduction, float penaltyDamageValue,
            float penaltyHealingDoneMultiplier, float penaltyTargets,
            float penaltyCooldownIncrease, float penaltyDuration, float penaltyChannelReduc,
            float penaltyConsumableCostIncreaseMultiplier, float penaltyConsumableCostIncreaseValue,
            float penaltyCritPerc, float penaltyCritDamageMultiplier
            )
        {
        }
#endif
        /// <summary>Base Damage Value (500 = 500.00 Damage)</summary>
        public float DamageBase { get; set; }
        /// <summary>Percentage Based Damage Bonus (1.5 = 150% damage)</summary>
        public float DamageBonus { get; set; }
        protected float HealingBase { get; set; }
        protected float HealingBonus { get; set; }
        /// <summary>Percentage Based Crit Chance Bonus (0.5 = 50% Crit Chance, capped between 0%-100%, factoring Boss Level Offsets)</summary>
        public virtual float BonusCritChance { get; set; }
        /// <summary>Percentage Based Crit Damage Bonus (1.5 = 150% damage)</summary>
        public float BonusCritDamage { get; set; }
        protected bool StanceOkFury { get; set; }
        protected bool StanceOkArms { get; set; }
        protected bool StanceOkDef { get; set; }
        protected bool UseReact { get; set; }
        protected CollectedCharacter CollChar { get; set; }
        public virtual CombatTable MHAtkTable { get; protected set; }
        public virtual CombatTable OHAtkTable { get; protected set; }
        public bool SwingsOffHand { get; protected set; }
        public float SwingsPerActivate { get; protected set; }
        private float _fightDur = -1f, _fightDurO20 = -1f, _fightDurU20 = -1f;
        public float FightDuration { get { if (_fightDur == -1) { _fightDur = CollChar.BossOpts.BerserkTimer; } return _fightDur; } }
        public float FightDurationO20 { get { if (_fightDurO20 == -1) { _fightDurO20 = FightDuration * TimeOver20Perc; } return _fightDurO20; } }
        public float FightDurationU20 { get { if (_fightDurU20 == -1) { _fightDurU20 = FightDuration * TimeUndr20Perc; } return _fightDurU20; } }
        private float /*_timeOpenerPerc = -1f,*/ _timeOver20Perc = -1f, _timeUndr20Perc = -1f;
        //public void SetTimeOpenerPerc(float numGCDs) { _timeOpenerPerc = GCDTime * numGCDs / _fightDur; }
        //public float TimeOpenerPerc { get { if (_timeOpenerPerc == -1f) { _timeOpenerPerc = 1f; } return _timeOpenerPerc; } }
        public float TimeOver20Perc { get { if (_timeOver20Perc == -1f) { _timeOver20Perc = 0.85f; } return _timeOver20Perc; } }
        public float TimeUndr20Perc { get { if (_timeUndr20Perc == -1f) { _timeUndr20Perc = 0.15f; } return _timeUndr20Perc; } }
        public bool UseForceTechHit { get; protected set; }
        protected bool UseHitTable { get; set; }
        public bool IsMaint { get; protected set; }
        public bool UsesGCD { get; protected set; }
        private bool validatedSet = false;
        public virtual bool Validated { get { return validatedSet; } }
        private bool setValidation() {
            if (AbilIterater != -1 /*&& !CollChar.CalcOpts.MaintenanceTree[AbilIterater]*/)
            {
                //validatedSet = false;
            }
            else if (ReqTalent && Talent2ChksValue < 1)
            {
                validatedSet = false;
            }
            else if (ReqMeleeWeap && (CollChar.Char.MainHand == null || CollChar.Char.MainHand.MaxDamage <= 0))
            {
                validatedSet = false;
            }
            else if (ReqMultiTargs && (!CollChar.BossOpts.MultiTargs || CollChar.BossOpts.Targets == null || CollChar.BossOpts.Targets.Count <= 0))
            {
                validatedSet = false;
            }
            else if (MustTargetIncapacitated || MustTargetSlowedOrImmobilized)
            {
                // TODO Find some way to make MustTargetSlowedOrImmobilized and MustTargetIncapacitated work against appropriate targets
                validatedSet = false;
            }
            else validatedSet = true;

            return validatedSet;
        }
        /// <summary>Number of times it can possibly be activated (# times actually used may be less or same).</summary>
        public virtual float Activates { get { return !Validated ? 0f : ActivatesOverride; } }
        /// <summary>
        /// Number of times it can possibly be activated (# times actually used may
        /// be less or same). This one does not check for stance/weapon info, etc.
        /// </summary>
        protected virtual float ActivatesOverride
        {
            get
            {
                float LatentGCD = 1.5f;// +CollChar.CalcOpts.Latency + (UseReact ? CollChar.CalcOpts.React / 1000f : CollChar.CalcOpts.AllowedReact);
                float GCDPerc = LatentGCD / ((Duration > CD ? Duration : CD) /*+ CollChar.CalcOpts.Latency*/ /*+ (UseReact ? CollChar.CalcOpts.React / 1000f : CollChar.CalcOpts.AllowedReact)*/);
                //float Every = LatentGCD / GCDPerc;
                if (ResourceCost > 0f)
                {
                    /*float rageSlip = (float)Math.Pow(Whiteattacks.MHAtkTable.AnyNotLand, Whiteattacks.AvoidanceStreak * Every);
                    float rageSlip2 = Whiteattacks.MHAtkTable.AnyNotLand / Every / Whiteattacks.AvoidanceStreak * RageCost / Whiteattacks.MHSwingRage;
                    float ret = FightDuration / Every * (1f - rageSlip);
                    return ret;*/
                    return Math.Max(0f, FightDuration / (LatentGCD / GCDPerc) * (1f /*- CollChar.Whiteattacks.RageSlip(LatentGCD / GCDPerc, RageCost)*/));
                }
                else return FightDuration / (LatentGCD / GCDPerc);
                /*double test = Math.Pow((double)Whiteattacks.MHAtkTable.AnyNotLand, (double)Whiteattacks.AvoidanceStreak * Every);
                return Math.Max(0f, FightDuration / Every * (1f - Whiteattacks.AvoidanceStreak));*/
            }
        }
        public float Healing { get { return !Validated ? 0f : HealingBase * (1f + (HealingBase > 0f ? HealingBonus : 0f)); } }
        public float HealingOnUse { get { return Healing * (1f + (HealingBase > 0f ? CollChar.CombatFactors.PlayersHealingReceivedBonusMultiplier : 0f)); } }
        //protected float AvgHealingOnUse { get { return HealingOnUse * Activates; } }
        protected float Damage { get { return !Validated ? 0f : DamageOverride; } }
        /// <summary>
        /// <Jothay> damage,s,1,1.87,0.167,0.207,0.01
        /// <Jothay> What is all that?
        /// <Jothay> That's for "abl.sith_warrior.force_scream"
        /// <nohh> in this case it's damage/healing,weapon/spell damage,multiplier,coefficient,hpMin,hpMax,modPct
        /// <nohh> and the formula is minDmg = Math.round(multiplier * (coefficient * CharactersDamageBonus + hpMin * stdDmg))
        /// where stdDmg is a value from the lookup table cbtStandardDamageInfo (that's a node name)
        /// <nohh> the multiplier is for DoTs and such that do their damage multiple times to show the total damage
        /// </summary>
        public virtual float DamageOverride
        {
            get
            {
                return Math.Max(0f, DamageBase * DamageBonus);
            }
        }
        public float DamageOnUse { get { return (Validated ? DamageOnUseOverride : 0f); } }

        private float calcDmgPart(int index, bool minMax, bool useH, float wdmg, float pldmgb)
        {
            if (index < 1 || index > 10) { return 0f; }
            if (DamageCoreType[index] == "") { return 0f; }
            //
            float T22a1 = (useH ? wdmg : 0f) * (1f + DamageCoreModPct[index])
                        + (minMax ? DamageCoreHPMax[index] : DamageCoreHPMin[index]) * cbtStandardDamage
                        + pldmgb * DamageCoreCoeff[index];
            //
            return T22a1;
        }

        private float cbtStandardDamage { get { return GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50]; } }

        public virtual float DamageOnUseOverride
        {
            get
            {
                //string T2 /*Type*/                     = "Single";
                //float T3 /*DD Coeff*/                 = DamageCoreCoeff     ; //1.300f;
                //float T4 /*Bleed Coeff*/              = DamageCoreCoeff * 2f; //2.600f;
                /*float T5*/ /*aMP1 - Ability*/           /*=*/ //DamageCoreModPct ;//-0.382f;
                //float T6 /*aMP2 - Ability*/           = DamageCoreModPct2;// 0.235f;
                //float T7 /*aMP - Talent*/             = 0;
                //float T8 /*aMP - Talent Bleed*/       = 0;
                //float T9 /*aMP - Talent Crit X*/      = 0;
                //float T10 /*sHP1 - Min*/              = DamageCoreHPMin  * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50];//209.300f;// =0.129999995*1610
                //float T11 /*sHP1 - Max*/              = DamageCoreHPMax  * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50];//209.300f;// =0.129999995*1610
                //float T12 /*sHP2 - Min*/              = DamageCoreHPMin2 * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50];//418.600f;// =0.25999999*1610
                //float T13 /*sHP2 - Max*/              = DamageCoreHPMax2 * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50];//418.600f;// =0.25999999*1610
                //float T14 /*MH Min*/                  = (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MinDamage : 0f); //= 284.000f;//
                //float T15 /*MH Max*/                  = (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MaxDamage : 0f); //= 426.000f;//
                //float T16 /*MH Min*/                  = (CallsForOffhand && CollChar.CombatFactors.useOH ? CollChar.CombatFactors.OH.MinDamage : 0f); //= 284.000f;//
                //float T17 /*MH Max*/                  = (CallsForOffhand && CollChar.CombatFactors.useOH ? CollChar.CombatFactors.OH.MaxDamage : 0f); //= 426.000f;//
                //float T18 /*Force*/                   = 0f;
                //float T19 /*(1-DR)*/                  = 0.065f;  // =1-Character!$AU$16
                //float T20 /*Crit chance*/             = 0.1778f; // =Character!$AH$6
                //float T21 /*Bleed Crit Chance*/       = 0;
                //float B77 = 1f;
                //float D77 = 0f;
                //float C77 = CombatFactors.PlayersDamageBonusFromStance(CollChar, (int)JuggStances.SoresuForm);
                //float C78 = 0f;
                //float T22 /*MH Min Damage*/           /*3251.8095*/     //=((T14 * (1f + DamageCoreModPct) + T10 + Character!$AH$5 * T$3) + (T14 * (1f + DamageCoreModPct) + T10 + Character!$AH$5 * T$3) + (T14 * (1f + T$6) + T12 + Character!$AH$5 * T$4) * Character!$AW$32)
                //                                           // * ($C$77 + ((T2="Single") ? ((CollChar.Talents as JuggernautTalents).SingleSaberMastery * 0.02f) : 0f) + $C$78 + $D$77)
                //                                           // * (1f + 0f/*talent->ability specific bonuses*/)
                //            =(    ((CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MinDamage : 0f) * (1f + DamageCoreModPct ) + DamageCoreHPMin  * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50] + CollChar.CombatFactors.PlayersDamageBonus * DamageCoreCoeff)
                //                + ((CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MinDamage : 0f) * (1f + DamageCoreModPct ) + DamageCoreHPMin  * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50] + CollChar.CombatFactors.PlayersDamageBonus * DamageCoreCoeff)
                //                + ((CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MinDamage : 0f) * (1f + DamageCoreModPct2) + DamageCoreHPMin2 * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50] + CollChar.CombatFactors.PlayersDamageBonus * DamageCoreCoeff*2f)
                //                * 1f)
                //            * (CombatFactors.PlayersDamageBonusFromStance(CollChar, (int)JuggStances.SoresuForm) + ((CollChar.Talents as JuggernautTalents).SingleSaberMastery * 0.02f) + 0f + 0f)
                //            * (1f + 0/*talent bonus*/);
                //T23 MH Max Damage           3602.5495     =((T15*(1+T$5)+T11+Character!$AH$5*T$3)+(T15*(1+T$5)+T11+Character!$AH$5*T$3)+(T15*(1+T$6)+T13+Character!$AH$5*T$4)*Character!$AW$32)*($C$77+IF(AND(OR(AdvancedClass={"Juggernaut","Guardian"}),OR(FormSelect={"Shien","Shii-Cho"}),T2="Single"),Character!$AJ$22*0.02,0)+$C$78+$D$77)*(1+T$7)
                //T24 OH Min Damage           0.0000
                //T25 OH Max Damage           0.0000
                //T26 Force Min Damage        0
                //T27 Force Max Damage        0
                //T28 MH Average              3426.3795     =AVERAGE(T22:T23)-0.8
                //T29 MH Average Crit         5416.8427     =T28*(Character!$AH$15+T$9)
                //T30 OH Average              0.0000
                //T31 OH Average Crit         0.0000
                //T32 Force Average           0
                //T33 Force Average Crit      0
                //T34 DoT Average             0
                //T35 DoT Average Crit        0
                //T36 DoT Duration            0
                //T37 Flurryblows             3
                //T38 Total Average DD        3790.5240     =T28*(Character!$AH$9-Character!$AU$11-T20-Character!$AU$9)+T29*(Character!$AH$9-Character!$AU$11)*T20+T28*(Character!$AH$9-Character!$AU$11)
                //                                           *Character!$AU$9*Character!$AU$10+T30*(Character!$AH$10-Character!$AU$11-T20-Character!$AU$9)+T31*(Character!$AH$10-Character!$AU$11)*T20
                //                                           +T30*(Character!$AH$10-Character!$AU$11)*Character!$AU$9*Character!$AU$10+T32*(Character!$AH$14-Character!$AU$12-T20-Character!$AU$9)
                //                                           +T33*(Character!$AH$14-Character!$AU$12)*T20+T32*(Character!$AH$14-Character!$AU$12)*Character!$AU$9*Character!$AU$10
                //T39 Total Average DoT       0
                //T40 Total Adj. Average      2463.8406     =(T28*(Character!$AH$9-Character!$AU$11-T20-Character!$AU$9)+T29*(Character!$AH$9-Character!$AU$11)*T20+T28*(Character!$AH$9-Character!$AU$11)
                //                                           *Character!$AU$9*Character!$AU$10+T30*(Character!$AH$10-Character!$AU$11-T20-Character!$AU$9)+T31*(Character!$AH$10-Character!$AU$11)*T20+T30
                //                                           *(Character!$AH$10-Character!$AU$11)*Character!$AU$9*Character!$AU$10+T32*(Character!$AH$14-Character!$AU$12-T20-Character!$AU$9)
                //                                           +T33*(Character!$AH$14-Character!$AU$12)*T20+T32*(Character!$AH$14-Character!$AU$12)*Character!$AU$9*Character!$AU$10)*T19
                //                                           +T34*(Character!$AH$14-Character!$AU$11-T21)+T35*(Character!$AH$14-Character!$AU$11)*T21+T34*(Character!$AH$14-Character!$AU$11)*Character!$AU$9*Character!$AU$10

#if FALSE
                float T22a1   = (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MinDamage : 0f) * (1f + DamageCoreModPct1)
                              + DamageCoreHPMin1 * cbtStandardDamage
                              + CollChar.CombatFactors.PlayersDamageBonus * DamageCoreCoeff1;
                float T22a2   = (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MinDamage : 0f) * (1f + DamageCoreModPct2)
                              + DamageCoreHPMin2 * cbtStandardDamage
                              + CollChar.CombatFactors.PlayersDamageBonus * DamageCoreCoeff1 * 2f;
                float T22a123 = (T22a1 + T22a1 + T22a2) * 1f;
#endif

                //float T22a123 = calcDmgPart(1, false, true, (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MinDamage : 0f), CollChar.CombatFactors.PlayersDamageBonus);
                //float T22b = CombatFactors.PlayersDamageBonusFromStance(CollChar, (int)JuggStances.SoresuForm)
                //    /* + ((CollChar.Talents as JuggernautTalents).SingleSaberMastery * 0.02f)*/ + 0f + 0f;
                //float T22c = 1f + 0/*talent bonus*/;
                //float minDmg = T22a123 * T22b * T22c;

#if FALSE
                float T23a1   = (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MaxDamage : 0f) * (1f + DamageCoreModPct1)
                              + DamageCoreHPMax1 * cbtStandardDamage
                              + CollChar.CombatFactors.PlayersDamageBonus * DamageCoreCoeff1;
                float T23a2   = (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MaxDamage : 0f) * (1f + DamageCoreModPct2)
                              + DamageCoreHPMax2 * cbtStandardDamage
                              + CollChar.CombatFactors.PlayersDamageBonus * DamageCoreCoeff1 * 2f;
                float T23a123 = (T23a1 + T23a1 + T23a2) * 1f;
#endif

                //float T23a123 = calcDmgPart(1, true, true, (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MaxDamage : 0f), CollChar.CombatFactors.PlayersDamageBonus);
                //float T23b = CombatFactors.PlayersDamageBonusFromStance(CollChar, (int)JuggStances.SoresuForm)
                //    /* + ((CollChar.Talents as JuggernautTalents).SingleSaberMastery * 0.02f)*/ + 0f + 0f;
                //float T23c    = 1f + 0/*talent bonus*/;
                //float maxDmg  = T23a123 * T23b * T23c;

                //float other = ((CollChar.CombatFactors.MH.MinDamage * (1f + DamageCoreCoeff  ) +  DamageCoreHPMin     + CollChar.CombatFactors.PlayersDamageBonus *  DamageCoreMultiplier)
                //            + ((CollChar.CombatFactors.MH.MinDamage * (1f + DamageCoreModPct ) +  DamageCoreHPMin     + CollChar.CombatFactors.PlayersDamageBonus *  DamageCoreMultiplier)
                //            + ((CollChar.CombatFactors.MH.MinDamage * (1f + DamageCoreModPct2) + (DamageCoreHPMin*2f) + CollChar.CombatFactors.PlayersDamageBonus * (DamageCoreMultiplier*2f))
                //               * 1f/*Character!$AW$32 Ravage statement could be 0 or 1*/)
                //               * (1f/*Soresu form modifiers*/ + ((CollChar.Talents as JuggernautTalents).SingleSaberMastery * 0.02f) + 0/*Bloodthirst dmg bonus*/ + 0/*Stance Bonus*/) * (1f + 0f/*Talent bonus damage multiplier*/)));

                /*float minDmg = 0f
                    + (CollChar.CombatFactors.useMH ? (UseSecCoeff ? DamageCoreMultiplier2 : DamageCoreMultiplier) * CollChar.CombatFactors.MH.MinDamage : 0f)
                    + (CallsForOffhand && CollChar.CombatFactors.useOH ? (UseSecCoeff ? DamageCoreMultiplier2 : DamageCoreMultiplier) * CollChar.CombatFactors.OH.MinDamage * 0.3f : 0f)
                    + ((UseSecCoeff ? DamageCoreCoeff2 : DamageCoreCoeff) * CollChar.CombatFactors.PlayersDamageBonus)
                    + ((UseSecCoeff ? DamageCoreHPMin2 : DamageCoreHPMin) * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50]);
                float maxDmg = 0f
                    + (CollChar.CombatFactors.useMH ? (UseSecCoeff ? DamageCoreMultiplier2 : DamageCoreMultiplier) * CollChar.CombatFactors.MH.MaxDamage : 0)
                    + (CallsForOffhand && CollChar.CombatFactors.useOH ? (UseSecCoeff ? DamageCoreMultiplier2 : DamageCoreMultiplier) * CollChar.CombatFactors.OH.MaxDamage * 0.3f : 0f)
                    + ((UseSecCoeff ? DamageCoreCoeff2 : DamageCoreCoeff) * CollChar.CombatFactors.PlayersDamageBonus)
                    + ((UseSecCoeff ? DamageCoreHPMax2 : DamageCoreHPMax) * GomLib.Tables.AbilityDamageTable.cbtStandardDamage["cbtToughness_player"][50]);*/

                //minDmg *= 1f + (UseSecCoeff ? DamageCoreModPct2 : DamageCoreModPct);
                //maxDmg *= 1f + (UseSecCoeff ? DamageCoreModPct2 : DamageCoreModPct);



                float minDmg = 0f, maxDmg = 0f;
                float stance = CombatFactors.PlayersDamageBonusFromStance(CollChar, (int)JuggStances.SoresuForm)
                        /* + ((CollChar.Talents as JuggernautTalents).SingleSaberMastery * 0.02f)*/ + 0f + 0f;
                float talent = 1f + 0/*talent bonus*/;
                for (int i = 1; i < 11; i++)
                {
                    if (DamageCoreType[i] == "") { continue; }
                    float min = calcDmgPart(i, false, true, (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MinDamage : 0f), CollChar.CombatFactors.PlayersDamageBonus);
                    float max = calcDmgPart(i, true , true, (CollChar.CombatFactors.useMH ? CollChar.CombatFactors.MH.MaxDamage : 0f), CollChar.CombatFactors.PlayersDamageBonus);
                    minDmg += min * stance * talent;
                    maxDmg += max * stance * talent;
                }

                float dmg = (minDmg + maxDmg) / 2f; // Base Damage
                dmg *= CollChar.CombatFactors.PlayersDamageBonusMultiplier; // Global Damage Bonuses
                dmg *= CollChar.CombatFactors.TargetsDamageReductionMultiplier; // Global Damage Penalties

                // Work the Attack Table
                float dmgDrop = (1f
                    - MHAtkTable.Miss    // no damage when being missed
                    - MHAtkTable.Dodge   // no damage when being dodged
                    - MHAtkTable.Parry   // no damage when being parried
                 // - MHAtkTable.Shield  // shield handled below
                    - MHAtkTable.Crit);  // crits  handled below

                //float dmgShield = dmg * MHAtkTable.Shield * CollChar.CombatFactors.TargetsShieldedDamageReductionMultiplier;//Partial damage when blocked
                float dmgCrit = dmg * MHAtkTable.Crit * (1f + CollChar.CombatFactors.CritDamageMultiplier) * BonusCritDamage;//Bonus   Damage when critting

                dmg *= dmgDrop;

                dmg += /*dmgShield +*/ dmgCrit;

                return dmg * AvgTargets;
            }
        }
        #endregion
        #region Functions
        protected void Initialize()
        {
            //ProcessAbilityTokens();
            if (!UseForceTechHit && UseHitTable && CanBeDodged && CanCrit && BonusCritChance == 0f)
            {
                MHAtkTable = CollChar.CombatFactors.AttackTableBasicMH;
                OHAtkTable = CollChar.CombatFactors.AttackTableBasicOH;
            }
            else
            {
                MHAtkTable = new AttackTable(CollChar.Char, CollChar.StatS, CollChar.CombatFactors, CollChar.BossOpts, this, true, !UseHitTable);
                OHAtkTable = new AttackTable(CollChar.Char, CollChar.StatS, CollChar.CombatFactors, CollChar.BossOpts, this, false, !UseHitTable);
            }
            setValidation();
        }
        public virtual float GetResourceUseOverDur(float acts)
        {
            if (!Validated) { return 0f; }
            return acts * ResourceCost;
        }
        //public float GetHealing() { if (!Validated) { return 0f; } return 0f; }
        public float GetAvgDamageOnUse(float acts)
        {
            if (!Validated) { return 0f; }
            return DamageOnUse * acts;
        }
        /*public virtual float GetDPS(float acts)
        {
            if (!Validated) { return 0f; }
            //float adou = GetAvgDamageOnUse(acts);
            return GetAvgDamageOnUse(acts) / FightDuration;
        }*/
        public virtual float GetDPS(float acts, float perc)
        {
            if (!Validated) { return 0f; }
            //float adou = GetAvgDamageOnUse(acts);
            return GetAvgDamageOnUse(acts) / (FightDuration * perc);
        }
        public virtual float GetTPS(float acts, float perc)
        {
            if (!Validated) { return 0f; }
            //float adou = GetAvgDamageOnUse(acts);
            return (GetAvgDamageOnUse(acts)
                    * (1f + CollChar.StatS.ThreatIncreaseMultiplier + DamageCoreThreatMod[1] /*+ (HighThreat ? 0.50f : 0f)*/)
                    * (1f - CollChar.StatS.ThreatReductionMultiplier))
                   / (FightDuration * perc);
        }
        public float GetAvgHealingOnUse(float acts)
        {
            if (!Validated) { return 0f; }
            return HealingOnUse * acts;
        }
        /*public virtual float GetHPS(float acts)
        {
            if (!Validated) { return 0f; }
            //float adou = GetAvgHealingOnUse(acts);
            return GetAvgHealingOnUse(acts) / FightDuration;
        }*/
        public virtual float GetHPS(float acts, float perc)
        {
            if (!Validated) { return 0f; }
            //float adou = GetAvgHealingOnUse(acts);
            return GetAvgHealingOnUse(acts) / (FightDuration * perc);
        }
        //public virtual float ContainCritValue_MH { get { return Math.Min(1f, CollChar.CombatFactors.Cmhycrit + BonusCritChance); } }
        //public virtual float ContainCritValue_OH { get { return Math.Min(1f, CollChar.CombatFactors.Cohycrit + BonusCritChance); } }
        /*public virtual float ContainCritValue(bool IsMH) {
            //float BaseCrit = IsMH ? CollChar.CombatFactors.Cmhycrit : CollChar.CombatFactors.Cohycrit;
            return Math.Min(1f, (IsMH ? CollChar.CombatFactors.Cmhycrit : CollChar.CombatFactors.Cohycrit) + BonusCritChance);
        }*/
        protected float GetXActs(AttackTableSelector i, float acts)
        {
            float retVal = 0f;
            switch (i)
            {
                case AttackTableSelector.Missed: { retVal = acts * MHAtkTable.Miss; break; }
                case AttackTableSelector.Dodged: { retVal = acts * MHAtkTable.Dodge; break; }
                case AttackTableSelector.Parried: { retVal = acts * MHAtkTable.Parry; break; }
                case AttackTableSelector.Blocked: { retVal = acts * MHAtkTable.Shield; break; }
                case AttackTableSelector.Critical: { retVal = acts * MHAtkTable.Crit; break; }
                case AttackTableSelector.Hit: { retVal = acts * MHAtkTable.Hit; break; }
                default: { break; }
            }
            return retVal;
        }
        public virtual string GenTooltip(float acts, float dpsO20, float dpsU20, float ttldpsperc)
        {
            //float Over20 = CollChar.CalcOpts.M_ExecuteSpam ? 1f - (float)BossOpts.Under20Perc : 1f;
            //float Undr20 = CollChar.CalcOpts.M_ExecuteSpam ?      (float)BossOpts.Under20Perc : 1f;

            float misses = GetXActs(AttackTableSelector.Missed, acts), missesPerc = (acts == 0f ? 0f : misses / acts);
            float dodges = GetXActs(AttackTableSelector.Dodged, acts), dodgesPerc = (acts == 0f ? 0f : dodges / acts);
            float parrys = GetXActs(AttackTableSelector.Parried, acts), parrysPerc = (acts == 0f ? 0f : parrys / acts);
            float blocks = GetXActs(AttackTableSelector.Blocked, acts), blocksPerc = (acts == 0f ? 0f : blocks / acts);
            float crits = GetXActs(AttackTableSelector.Critical, acts), critsPerc = (acts == 0f ? 0f : crits / acts);
            float hits = GetXActs(AttackTableSelector.Hit, acts), hitsPerc = (acts == 0f ? 0f : hits / acts);

            bool showmisss = misses > 0f;
            bool showdodge = CanBeDodged && dodges > 0f;
            bool showparry = CanBeParried && parrys > 0f;
            bool showblock = CanBeShielded && blocks > 0f;
            bool showcrits = CanCrit && crits > 0f;

            string tt = string.Format(@"*{0}*Cast Time: {1}, CD: {2}, Rage {16}: {3}

{4:000.00} Activates over Attack Table:{5}{6}{7}{8}{9}{10}{11}

Targets Hit: {12:0.00}
DPS: {13:0.00}|{14:0.00}
Percentage of Total DPS: {15:00.00%}",
            Name,
            (CastTime != -1 ? string.Format("{0:0.00}", CastTime) : "Instant"),
            (CD != -1 ? string.Format("{0:0.00}", CD) : "None"),
            (ResourceCost != -1 ? string.Format("{0:0.00}", (-1f * ResourceCost)) : "None"),
            acts,
            showmisss ? string.Format("\r\n- {0:000.00} : {1:00.00%} : Missed", misses, missesPerc) : "",
            showdodge ? string.Format("\r\n- {0:000.00} : {1:00.00%} : Dodged", dodges, dodgesPerc) : "",
            showparry ? string.Format("\r\n- {0:000.00} : {1:00.00%} : Parried", parrys, parrysPerc) : "",
            showblock ? string.Format("\r\n- {0:000.00} : {1:00.00%} : Blocked", blocks, blocksPerc) : "",
            "", // ignore glance
            showcrits ? string.Format("\r\n- {0:000.00} : {1:00.00%} : Crit", crits, critsPerc) : "",
                        string.Format("\r\n- {0:000.00} : {1:00.00%} : Hit", hits, hitsPerc),
            (Targets != -1 ? AvgTargets : 1),
            (dpsO20 > 0 ? dpsO20 : 0),
            (dpsU20 > 0 ? dpsU20 : 0),
            (ttldpsperc > 0 ? ttldpsperc : 0),
            ResourceCost != 1 && ResourceCost > 0 ? "Cost" : "Generated");

            return tt;
        }
        #endregion
    }
    public class NullAbility : ClassAbility
    {
        public override CombatTable MHAtkTable { get { return CombatTable.NULL; } protected set { ; } }
        public override CombatTable OHAtkTable { get { return CombatTable.NULL; } protected set { ; } }
        //public override float RageUseOverDur { get { return 0; } }
        protected override float ActivatesOverride { get { return 0; } }
        public override float DamageOnUseOverride { get { return 0; } }
        public override float DamageOverride { get { return 0; } }
        public override string GenTooltip(float acts, float dpsO20, float dpsU20, float ttldpsperc) { return String.Empty; }
        public override float GetResourceUseOverDur(float acts) { return 0; }
        public override bool Validated { get { return false; } }
        public override float Activates { get { return 0; } }
        //public override float GetDPS(float acts) { return 0; }
        public override float GetDPS(float acts, float perc) { return 0; }
    }
    public class DoT : ClassAbility
    {
        // Constructors
        public DoT() { }
        // Variables
        public float TimeBtwnTicks { get; set; } // In Seconds
        protected float addMisses;
        protected float addDodges;
        protected float addParrys;
        // Functions
        public virtual float InitialDamage { get { return 0f; } }
        public virtual float TickSize { get { return 0f; } }
        public virtual float TtlTickingTime { get { return Duration; } }
        public virtual float TickLength { get { return TimeBtwnTicks; } }
        public virtual float NumTicks { get { return TtlTickingTime / TickLength; } }
        //public virtual float DmgOverTickingTime { get { return TickSize * NumTicks; } }
        public virtual float GetDmgOverTickingTime(float acts) { return TickSize * (NumTicks * acts); }
        public override float GetDPS(float acts, float perc)
        {
            return GetDmgOverTickingTime(acts) / (FightDuration * perc);
        }
        //public virtual float DPS { get { return TickSize / TickLength; } }
    }
    public class BuffEffect : ClassAbility
    {
        // Constructors
        public BuffEffect()
        {
            IsMaint = true;
            Effect = null;
            Effect2 = null;
        }
        // Variables
        protected float addMisses;
        protected float addDodges;
        protected float addParrys;
        // Get/Set
        public SpecialEffect Effect { get; set; }
        public SpecialEffect Effect2 { get; set; }
        private static Dictionary<Trigger, float> chances = new Dictionary<Trigger, float>() { { Trigger.Use, 0f }, };
        private static Dictionary<Trigger, float> intervals = new Dictionary<Trigger, float>();
        // Functions
        public virtual Stats AverageStats
        {
            get
            {
                if (!Validated) { return new Stats(); }
                if (Effect == null && Effect2 == null) { return new Stats(); }
                intervals[Trigger.Use] = MHAtkTable.Hit + MHAtkTable.Crit;
                Stats bonus = new Stats();
                if (Effect  != null) { bonus.Accumulate(Effect.GetAverageStats( chances, intervals, 1.5f, FightDuration)); }
                if (Effect2 != null) { bonus.Accumulate(Effect2.GetAverageStats(chances, intervals, 1.5f, FightDuration)); }
                return bonus;
            }
        }
    }
}
#if FALSE
namespace Rage.Base.Abilities.sith_warrior
{
    /// <summary>
    /// Inflicts 736-798 damage with a series of quick melee attacks. Builds 2 Rage. Attacks with both weapons if dual wielding.
    /// </summary>
    public sealed class Assault : ClassAbility
    {
        public static new string SName { get { return @"Assault"; } }
        public static new string SDesc { get { return @"Inflicts 571-715 damage with a series of quick melee attacks. Builds 2 Rage. Attacks with both weapons if dual wielding."; } }
        public static new string SIcon { get { return @"sunderingAssault"; } }
        public static new string SFqn { get { return @"abl.sith_warrior.sundering_assault"; } }
        public static new int SSpellId { get { return 188082; } }
        public override string Name { get { return SName; } }
        public override string Desc { get { return SDesc; } }
        public override string Icon { get { return SIcon; } }
        public override string Fqn { get { return SFqn; } }
        public override int SpellId { get { return SSpellId; } }
        /// <summary>
        /// Inflicts 736-798 damage with a series of quick melee attacks. Builds 2 Rage. Attacks with both weapons if dual wielding.
        /// </summary>
        public Assault(CollectedCharacter collChar)
        {
            CollChar = collChar;
            //
            AbilIterator = Maintenance.sith_warrior_Assault;
            AbilityTokens = "damage,w,1,1,0,0,0;"; // Modifies the ability in some way
            TalentTokens = "'damage,w,1,1,0,0,0'";
            ApCost = -2;
            ApType = GomLib.Models.ApType.Rage;
            CastingTime = 0f; // In Seconds
            ChannelingTime = 0f; // In Seconds
            Cooldown = 1.5f; // In Seconds
            DescriptionId = 4294967296;
            EnergyCost = 0;
            ForceCost = 0;
            GCD = -1f;
            GcdOverride = false;
            IgnoreAlacrity = true;
            IsHidden = false;
            IsPassive = false;
            Level = 0;
            LineOfSightCheck = true;
            MaxRange = 0.4f; // In Meters
            MinRange = 0f; // In Meters
            ModalGroup = 0;
            NameId = 0;
            NodeId = 0;
            Pushback = true;
            SharedCooldown = 16141130244599833484;
            TargetArc = 180;
            TargetArcOffset = 0;
            TargetRule = GomLib.Models.TargetRule.Attackable;
            Duration = 0f;
            DamageCoreType = "s";
            DamageCoreMultiplier = 1f;
            DamageCoreCoeff = 1.00f;
            DamageCoreHPMin = 0.0f;
            DamageCoreHPMax = 0.0f;
            DamageCoreModPct = 0.0f;
            DamageCoreType2 = "s";
            DamageCoreMultiplier2 = 1f;
            DamageCoreCoeff2 = 1.00f;
            DamageCoreHPMin2 = 0.0f;
            DamageCoreHPMax2 = 0.0f;
            DamageCoreModPct2 = 0.0f;
            //
            Initialize();
        }
    }
}
#endif
